import React, { Component } from 'react';
import { Chart, Axis, Tooltip, Geom, Label, Legend, Guide } from 'bizcharts';
import { DataView } from '@antv/data-set';
import ResizeObserver from 'resize-observer-polyfill';
import {
  themeLight,
  themeDark,
  commonConfig,
  axisConfig,
  legendConfig,
  barConfig,
  guideLineConfig,
  fitFontSize,
} from '../config';
import styles from '../index.less';

const {
  defaultTheme,
  defaultFontFamily,
  defaultTickCount,
  defaultChartUnitFontSize,
  defaultValueOffset,
  defaultValueFontSize,
  defaultPaddingTop,
} = commonConfig;
const { defaultXLabelFontSize, defaultXLabelOffset, defaultYLabelFontSize } = axisConfig;
const {
  defaultLegendOffsetY,
  defaultLegendFontSize,
  defaultLegendLineHeight,
  defaultLegendItemGap,
  defaultLegendMarkerCircle,
} = legendConfig;
const { defaultBarAdjust, defaultBarShape, defaultBarWidth, defaultBarOpacity } = barConfig;
const { defaultGuideLineWidth, defaultGuideLineColors } = guideLineConfig;

class Bar extends Component {
  state = {
    height: 0,
    viewportScale: window.viewportScale,
  };

  componentDidMount() {
    this.resizeObserver();
    window.addEventListener('resize', this.resize, { passive: true });
  }

  componentWillUnmount() {
    window.removeEventListener('resize', this.resize);
  }

  handleRoot = n => {
    this.root = n;
  };

  handleRef = n => {
    this.node = n;
  };

  resize = () => {
    this.setState({ viewportScale: window.viewportScale });
  };

  resizeObserver() {
    const ro = new ResizeObserver(entries => {
      const { width, height } = entries[0].contentRect;
      this.setState(preState => {
        if (preState.width !== width || preState.height !== height) {
          return {
            height,
          };
        }
        return null;
      });
    });
    if (this.root) {
      ro.observe(this.root);
    }
  }

  render() {
    const { height: stateHeight, viewportScale } = this.state;
    const { theme = defaultTheme } = this.props;
    const {
      defaultColors,
      defaultColor,
      defaultChartUnitColor,
      defaultLineColor,
      defaultGridColor,
      defaultValueColor,
      defaultXLabelColor,
      defaultYLabelColor,
      defaultLegendColor,
    } = theme === 'dark' ? themeDark : themeLight;
    const {
      height: propsHeight,
      style = {},
      forceFit = true,
      data = [],
      padding = [defaultPaddingTop * viewportScale, 'auto', 'auto'],
      hiddenYLabel = false, // 是否隐藏y轴标签
      showValue = false, // 柱子顶端显示数值
      valueOffset = defaultValueOffset, // 柱状图数值距柱子顶端距离
      hiddenXLabel = false, // 是否隐藏x轴标签(包括轴线）
      hiddenXLabelValue = false, // 是否隐藏x轴标签
      xLineColor = defaultLineColor, // x轴线颜色
      xLabelOffset = defaultXLabelOffset, // x轴标签距x轴距离
      xLabelAutoRotate = false, // 是否自动旋转
      xLabelRotate = 0, // 旋转角度
      geomStyle = {}, // 为Geom添加自定义样式，设置cursor之类的

      groupField, // 分组字段（Legend）
      colors = defaultColors, // 分组颜色数组
      color = defaultColor,

      hiddenLegend = false, // 是否隐藏Legend
      legendOffsetY = defaultLegendOffsetY, // 垂直方向偏移
      legendFontSize = defaultLegendFontSize, // Legend字体大小
      legendColor = defaultLegendColor, // Legend字体颜色

      fieldExpand, // 字段展开中文名称对应
      x = 'x', // x轴字段名
      y = 'y', // y轴字段名
      showTooltip = true, // 显示tooltip
      showTooltipTitle = true, // 显示tooltip title
      adjust = defaultBarAdjust,
      shape = defaultBarShape,

      size = defaultBarWidth, // 每根柱子的宽度

      unit = '',
      showYUnit = false, // 为y轴标签添加单位
      showTooltipUnit = true, // 为tooltip添加单位
      chartUnitPosition, // 设置图表总单位位置
      chartUnitColor = defaultChartUnitColor, // 图表总单位颜色
      chartUnitFontSize = defaultChartUnitFontSize, // 图表总单位字体大小

      fontSize, // 同时设置以下几种字体大小，下面的设置将无效
      xLabelFontSize = defaultXLabelFontSize, // x轴标签字体大小
      yLabelFontSize = defaultYLabelFontSize, // y轴标签字体大小
      valueFontSize = defaultValueFontSize, // 柱状图数值字体大小
      labelColor, // 标签颜色
      tickCount = defaultTickCount, // 网格线条数
      gridColor = defaultGridColor, // 网格线颜色

      onChartClick, // 图表点击事件

      xScale = {},
      yScale = {},

      guideLine = [], // 辅助线
    } = this.props;

    const scale = {
      [x]: {
        type: 'cat',
        ...xScale,
      },
      [y]: {
        formatter(val) {
          return (val || val === 0) && (showYUnit ? val.toFixed(0) + unit : val.toFixed(0));
        },
        tickCount,
        ...yScale,
      },
    };

    // 字段展开
    const dv = new DataView();
    if (fieldExpand && fieldExpand.length) {
      dv.source(data);
      const fields = [];
      fieldExpand.map(({ field, rename }) => {
        dv.transform({
          type: 'rename',
          map: { [field]: rename },
        });
        fields.push(rename);
      });
      dv.transform({
        type: 'fold',
        fields, // 展开字段集
        key: 'group', // key字段
        value: 'y', // value字段
        retains: [x],
      });
    }

    const height = propsHeight || stateHeight;

    return (
      <div
        className={styles.bar}
        style={{ height: height * viewportScale, ...style }}
        ref={this.handleRoot}
        key={this.root}
      >
        <div ref={this.handleRef}>
          <Chart
            scale={scale}
            height={height * viewportScale}
            forceFit={forceFit}
            data={fieldExpand && fieldExpand.length ? dv : data}
            padding={padding}
            onTooltipChange={ev => {
              const { items } = ev; // tooltip显示的项
              const newItems = items.slice();
              if (newItems && newItems.length) {
                items.splice(0);
                newItems.forEach(item => {
                  items.push({
                    ...item,
                    name: newItems.length === 1 ? item.title : item.name,
                    value:
                      item.value === 0 || item.value
                        ? unit && showTooltipUnit && !showYUnit
                          ? item.value + unit
                          : item.value
                        : '--',
                  });
                });
              }
            }}
            onPlotClick={({ data: barData }) => {
              if (barData && onChartClick) {
                onChartClick(barData._origin);
              }
            }}
          >
            <Axis
              name={x}
              visible={!hiddenXLabel}
              line={{
                stroke: xLineColor,
              }}
              tickLine={null}
              label={
                hiddenXLabelValue
                  ? false
                  : {
                      autoRotate: xLabelAutoRotate,
                      rotate: xLabelRotate,
                      offset: xLabelOffset * viewportScale,
                      textStyle: {
                        fill: labelColor || defaultXLabelColor,
                        fontSize: fitFontSize(fontSize || xLabelFontSize),
                        fontFamily: defaultFontFamily,
                      },
                    }
              }
            />
            <Axis
              name={y}
              visible={!hiddenYLabel}
              label={
                hiddenYLabel
                  ? false
                  : {
                      textStyle: {
                        fill: labelColor || defaultYLabelColor,
                        fontSize: fitFontSize(fontSize || yLabelFontSize),
                        fontFamily: defaultFontFamily,
                      },
                    }
              }
              grid={{
                lineStyle: {
                  stroke: gridColor,
                  lineWidth: 1,
                  // lineDash: [4, 0],
                },
                zeroLineStyle: {
                  stroke: gridColor,
                  // lineDash: [2, 4]
                },
              }}
            />
            <Legend
              visible={!hiddenLegend}
              position="top"
              offsetY={legendOffsetY * viewportScale}
              useHtml
              g2-legend-list-item={{
                lineHeight: `${defaultLegendLineHeight * viewportScale}px`,
                fontSize: `${legendFontSize * viewportScale}px`,
                fontFamily: defaultFontFamily,
                color: legendColor,
                marginRight: `${defaultLegendItemGap * viewportScale}px`,
                marginBottom: 0,
              }}
              g2-legend-marker={defaultLegendMarkerCircle}
            />
            <div>{showTooltip && <Tooltip showTitle={showTooltipTitle} crosshairs={false} />}</div>
            <Geom
              style={{ cursor: onChartClick ? 'pointer' : 'default', ...geomStyle }}
              type="interval"
              position={`${x}*${y}`}
              color={groupField ? [groupField, colors] : color}
              size={size * viewportScale}
              opacity={defaultBarOpacity}
              adjust={adjust}
              shape={shape}
            >
              {showValue && (
                <Label
                  content={y}
                  offset={valueOffset * viewportScale}
                  textStyle={{
                    fill: defaultValueColor,
                    fontSize: fitFontSize(fontSize || valueFontSize),
                    fontFamily: defaultFontFamily,
                  }}
                />
              )}
              {guideLine.length > 0 && (
                <Guide>
                  {guideLine.map(({ value, color: guideLineColor, content, offsetX }, index) => (
                    <Guide.Line
                      key={index}
                      top
                      start={['min', value]}
                      end={['max', value]}
                      lineStyle={{
                        stroke:
                          guideLineColor ||
                          defaultGuideLineColors[index] ||
                          (theme === 'dark' ? '#fff' : '#000'),
                        lineDash: [0, 0],
                        lineWidth: defaultGuideLineWidth * viewportScale,
                      }} // 图形样式配置
                      text={{
                        position: 'end', // 文本的显示位置
                        style: {
                          fill:
                            guideLineColor ||
                            defaultGuideLineColors[index] ||
                            (theme === 'dark' ? '#fff' : '#000'),
                          fontSize: fitFontSize(legendFontSize),
                          fontFamily: defaultFontFamily,
                        }, // 文本图形样式配置
                        content, // 文本的内容
                        offsetX: offsetX || 5 * viewportScale,
                        offsetY: (legendFontSize * viewportScale) / 2, // y 方向的偏移量
                      }}
                    />
                  ))}
                </Guide>
              )}
            </Geom>
          </Chart>
        </div>
        {!!chartUnitPosition && unit && (
          <span
            className={styles.unit}
            style={{
              color: chartUnitColor,
              fontSize: chartUnitFontSize * viewportScale,
              left: 0,
              ...chartUnitPosition,
            }}
          >
            {`(${unit})`}
          </span>
        )}
      </div>
    );
  }
}

export default Bar;
